package com.scs.application.modules.wm.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.scs.application.consts.GlobalConsts;
import com.scs.application.consts.SerialKeys;
import com.scs.application.core.exception.BusinessException;
import com.scs.application.core.utils.DateUtils;
import com.scs.application.core.utils.StringUtils;
import com.scs.application.core.utils.UserUtils;
import com.scs.application.modules.cfg.utils.ParameterUtils;
import com.scs.application.modules.sys.model.RestResult;
import com.scs.application.modules.thirdparty.dto.HrpStockItemDTO;
import com.scs.application.modules.thirdparty.service.HrpService;
import com.scs.application.modules.wm.entity.*;
import com.scs.application.modules.wm.mapper.TertiaryStockCheckMapper;
import com.scs.application.modules.wm.mapper.WorkOrderMapper;
import com.scs.application.modules.wm.service.TertiaryStockCheckItemService;
import com.scs.application.modules.wm.service.TertiaryStockCheckService;
import com.scs.application.core.service.BaseServiceImpl;
import com.scs.application.modules.wm.service.TertiaryStockService;
import com.google.common.collect.Lists;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.Date;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * <p>
 * 三级库盘点 服务实现类
 * </p>
 */
@Service
public class TertiaryStockCheckServiceImpl extends BaseServiceImpl<TertiaryStockCheckMapper, TertiaryStockCheck> implements TertiaryStockCheckService {

    @Resource
    private WorkOrderMapper workOrderMapper;

    @Resource
    private TertiaryStockService stockService;

    @Resource
    private TertiaryStockCheckItemService stockCheckItemService;

    @Resource
    private HrpService hrpService;

    @Override
    public boolean saveOrUpdate(TertiaryStockCheck entity) {
        if (StringUtils.isBlank(entity.getBusKey())) {
            entity.setBusKey(serialRuleAdapter.getSerialRuleService().generateCode(SerialKeys.STOCK_CHECK));
        }
        if (StringUtils.isBlank(entity.getBusUser())) {
            entity.setBusUser(UserUtils.currentUser().getName());
        }
        if (entity.getFlagFinished() == null ||entity.getFlagFinished() != true) {
            List<TertiaryStockCheck> list = this.list(Wrappers.<TertiaryStockCheck>query().eq("reagent_team_id",entity.getReagentTeamId()).eq("flag_finished", false));
            if(list != null && list.size() > 0) {
                throw  new BusinessException("该试剂组已有盘点单，请勿重复盘点");
            }
        }
        if (StringUtils.isBlank(entity.getId())) {
            QueryWrapper queryWrapper = new QueryWrapper<TertiaryStock>().gt("sku_qty", 0);
            if (StringUtils.isNotBlank(entity.getMatrId())) { queryWrapper.eq("matr_id",entity.getMatrId()); }
            if (StringUtils.isNotBlank(entity.getReagentTeamId())) { queryWrapper.eq("reagent_team_id",entity.getReagentTeamId()); }
            if (StringUtils.isNotBlank(entity.getCheckType()) && !GlobalConsts.CheckType.all.equals(entity.getCheckType())) {
                String busDateBegin=null;
                String busDateEnd=null;
                String dateStr;
                String checkType="";
                switch (entity.getCheckType()){
                    case GlobalConsts.CheckType.today:
                        checkType="今天库存变动";
                        dateStr = DateUtils.format(new Date(),"yyyy-MM-dd");
                        busDateBegin=dateStr+" 00:00:00";
                        busDateEnd=dateStr+" 23:59:59";
                        break;
                    case GlobalConsts.CheckType.yesterday:
                        checkType="昨天库存变动";
                        dateStr = DateUtils.format(DateUtils.addDays(new Date(), -1),"yyyy-MM-dd");
                        busDateBegin=dateStr+" 00:00:00";
                        busDateEnd=dateStr+" 23:59:59";
                        break;
                    case GlobalConsts.CheckType.thisWeek:
                        checkType="本周库存变动";
                        dateStr = DateUtils.format(DateUtils.getFirstDayOfWeek(new Date()),"yyyy-MM-dd");
                        busDateBegin=dateStr+" 00:00:00";
                        dateStr = DateUtils.format(DateUtils.getLastDayOfWeek(new Date()),"yyyy-MM-dd");
                        busDateEnd=dateStr+" 23:59:59";
                        break;
                    case GlobalConsts.CheckType.thisMonth:
                        checkType="本月库存变动";
                        dateStr = DateUtils.format(DateUtils.getFirstDayOfMonth(new Date()),"yyyy-MM-dd");
                        busDateBegin=dateStr+" 00:00:00";
                        dateStr = DateUtils.format(DateUtils.getLastDayOfMonth(new Date()),"yyyy-MM-dd");
                        busDateEnd=dateStr+" 23:59:59";
                        break;
                    case GlobalConsts.CheckType.lastMonth:
                        checkType="上月库存变动";
                        //上月第一天
                        Date dateLastMonth = DateUtils.getFirstDayOfMonth(DateUtils.addMonth(new Date(), -1)) ;
                        dateStr = DateUtils.format(DateUtils.getFirstDayOfMonth(dateLastMonth),"yyyy-MM-dd");
                        busDateBegin=dateStr+" 00:00:00";
                        dateStr = DateUtils.format(DateUtils.getLastDayOfMonth(dateLastMonth),"yyyy-MM-dd");
                        busDateEnd=dateStr+" 23:59:59";
                        break;
                    default:
                        throw  new BusinessException("未实现的盘点类型【%s】",entity.getCheckType());
                }

                QueryWrapper wrapper = Wrappers.<TertiaryStock>query();
                wrapper.between("in_time",busDateBegin,busDateEnd);
                wrapper.eq("reagent_team_id",entity.getReagentTeamId());
                if (StringUtils.isNotBlank(entity.getMatrId())) { wrapper.eq("matr_id",entity.getMatrId()); }
                List<TertiaryStock> listItem = stockService.list(wrapper);
                if (listItem == null || listItem.size() < 1) {
                    String errMsg ="试剂组【"+entity.getReagentTeamName()+"】\n";
                    if (StringUtils.isNotBlank(entity.getMatrId())) {
                        errMsg+="试剂【"+entity.getMatrName()+"】\n";
                    }
                    errMsg+="【"+checkType+"】";
                    throw new BusinessException(errMsg+"为0，无需盘点!");
                }

                queryWrapper.in("id",listItem.stream().map(TertiaryStock::getId).collect(Collectors.toList()));
            }

            List<TertiaryStock> stockList = stockService.list(queryWrapper);
            if (stockList == null || stockList.size() < 1){
                String errMsg ="试剂组【"+entity.getReagentTeamName()+"】\n";
                if (StringUtils.isNotBlank(entity.getMatrId())) {
                    errMsg+="试剂【"+entity.getMatrName()+"】\n";
                }
                throw new BusinessException(errMsg+"未找到相关库存，无需盘点!");
            }

            double stockNum = stockList.size();
            entity.setStockNum(stockNum).setStockLoss(0d).setStockSurplus(0d).setStockUnknown(stockNum).setStockNormal(0d);
            super.saveOrUpdate(entity);

            //初始化盘点明细列表
            List<TertiaryStockCheckItem> itemAddList = Lists.newArrayList();
            stockList.stream().forEach(stock -> {
                TertiaryStockCheckItem stockCheckItem = new TertiaryStockCheckItem();
                BeanUtils.copyProperties(stock, stockCheckItem);
                stockCheckItem.setCheckId(entity.getId())
                        .setCheckStatus(-9)
                        .setStockId(stock.getId())
                        .setCheckId(entity.getId())
                        .setId(null);
                itemAddList.add(stockCheckItem);
            });
            stockCheckItemService.saveBatch(itemAddList);
        } else {
            if (entity.getFlagFinished() != null && entity.getFlagFinished()){
                TertiaryStockCheck stockCheck = this.getById(entity.getId());
                if (stockCheck.getFlagFinished() != null && stockCheck.getFlagFinished()) {

                    throw new BusinessException("该盘点单已结束盘点，操作人：%s，操作时间：%s", stockCheck.getModifier(), stockCheck.getGmtModified());
                }
                stockCheckItemService.update(Wrappers.<TertiaryStockCheckItem>update().set("check_status",-1)
                        .eq("check_id",entity.getId()).eq("check_status","-9"));
                int count = stockCheckItemService.count(Wrappers.<TertiaryStockCheckItem>query()
                        .eq("check_status", "-1").eq("check_id", entity.getId()));
                entity.setStockLoss((double) count).setStockUnknown(0D);
                super.saveOrUpdate(entity);
            }
        }
        return true;
    }

    @Override
    public void haveSn(String sn) {
        TertiaryStock stock = stockService.getOne(Wrappers.<TertiaryStock>query().eq("sn", sn).or().eq("IFNULL(rfid,'')", sn), false);
        if (stock == null) {
            throw  new BusinessException("库存中未找到该标签【%s】，请检查",sn);
        }
    }

    @Override
    public RestResult scan(String uc, String checkId) {
        RestResult restResult = RestResult.ok();
        TertiaryStockCheck stockCheck = this.getById(checkId);
        if (stockCheck ==  null) throw new BusinessException("所操作的盘点单不存在或者已被删除");
        if (stockCheck.getFlagFinished() != null && stockCheck.getFlagFinished()) { throw new BusinessException("该盘点单【%s】已结束盘点，请勿重复操作",stockCheck.getBusKey()); }
        this.haveSn(uc);
        TertiaryStock stock = stockService.getStockByUniqueCode(uc);

        TertiaryStockCheckItem stockCheckItem = new TertiaryStockCheckItem();

        stockCheckItem.setCheckStatus(0);
        //盘点状态 0：正常 1：盘盈 -1：盘亏
        String  msg = "正常";
        int checkStatus= 0;
        if (stock ==null || stock.getPackageQty() < 1) {
            //无库存
            stockCheckItem.setCheckStatus(-1);
            if (stock != null) {
                int count = stockCheckItemService.count(Wrappers.<TertiaryStockCheckItem>query().ne("check_status","-9").eq("check_id",checkId).eq("stock_id",stock.getId()));
                if (count >0) { throw new BusinessException("该唯一码【%s】已盘点过，请勿重复操作",stock.getSn()== null ?stock.getRfid():stock.getSn()); }
                stockCheckItem=stockCheckItemService.getOne(Wrappers.<TertiaryStockCheckItem>query().eq("check_id",checkId).eq("stock_id",stock.getId()));
                if (stockCheckItem == null) {
                    stockCheckItem = new TertiaryStockCheckItem();
                    BeanUtils.copyProperties(stock, stockCheckItem);
                }
                msg = "盘亏【无库存】";
                checkStatus = -1;

                //没库存，盘盈
                if (stock.getPackageQty() <= 0 ){
                    checkStatus = 1;
                    msg = "盘盈【无库存】";
                }
            }else {
                int count = stockCheckItemService.count(Wrappers.<TertiaryStockCheckItem>query().ne("check_status","-9").eq("check_id",checkId).eq("stock_id",stock.getId()));
                if (count >0) { throw new BusinessException("该唯一码【%s】已盘点过，请勿重复操作",uc); }
                msg = "盘亏【无库存记录】";
                stockCheckItem=stockCheckItemService.getOne(Wrappers.<TertiaryStockCheckItem>query().eq("check_id",checkId).eq("stock_id",stock.getId()));
                if (stockCheckItem == null) {
                    stockCheckItem = new TertiaryStockCheckItem();
                }
                stockCheckItem.setSn(uc).setStockId("-1").setLineId("-1").setSupplierId("-1").setSupplierName("未知").setMatrName("未知");
                checkStatus = -1;
            }
        }else {
            //有库存
            int count = stockCheckItemService.count(Wrappers.<TertiaryStockCheckItem>query().ne("check_status","-9").eq("check_id",checkId).eq("stock_id",stock.getId()));
            if (count >0) { throw new BusinessException("该唯一码【%s】已盘点过，请勿重复操作",stock.getSn()== null ?stock.getRfid():stock.getSn()); }
            stockCheckItem=stockCheckItemService.getOne(Wrappers.<TertiaryStockCheckItem>query().eq("check_id",checkId).eq("stock_id",stock.getId()));
            if (stockCheckItem == null) {
                stockCheckItem = new TertiaryStockCheckItem();
                BeanUtils.copyProperties(stock, stockCheckItem);
            }
            // 不同试剂组
            if (!stock.getReagentTeamId().equals(stockCheck.getReagentTeamId())) {
                stockCheckItem.setCheckStatus(1);
                msg = "盘盈【不同试剂组】，该唯一码库存所在试剂组为："+stock.getReagentTeamName();
                checkStatus =1;
            }

            //仓库盘点
//            if (!stock.getWarehouseId().equals(stockCheck.getWarehouseId())) { //不同仓库
//                stockCheckItem.setCheckStatus(1);
//                msg = "盘盈【不同仓库】，该唯一码库存所在仓库为："+stock.getWarehouseName();
//                checkStatus =1;
//            }
        }

        stockCheckItem.setCheckStatus(checkStatus).setCheckId(checkId).setStockId(stock.getId());
        stockCheckItemService.saveOrUpdate(stockCheckItem);

        restResult.setMsg(msg);

        //更新盘盈盘亏未知
        restResult.setData(this.updateMain(stockCheck));
        return restResult;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public RestResult RFIDScan(List<String> ucs, String checkId) {
        long beginTime = System.currentTimeMillis();
        RestResult restResult = RestResult.ok();
        //截取尾部F
        List<String> ucList = ucs.stream().flatMap(s -> {
            String rfid = selectF(s);
            return Stream.of(rfid);
        }).collect(Collectors.toList());
        //获取当前盘点单对应的库存盘点单信息
        TertiaryStockCheck stockCheck = this.getById(checkId);
        String msgBuffer = "";
        //盘点状态 0：正常 1：盘盈 -1：盘亏 ， -9： 未盘， -2：重复盘点
        int numLoss = 0, numSurplus = 0, numUnknown = 0, numNormal = 0, numNrepetitive = 0;
        if (stockCheck == null) { throw new BusinessException("所操作的盘点单不存在或者已被删除"); }
        if (stockCheck.getFlagFinished() != null && stockCheck.getFlagFinished()) {
            throw new BusinessException("该盘点单【%s】已结束盘点，请勿重复操作", stockCheck.getBusKey());
        }
        // 查询盘库单明细
        List<TertiaryStockCheckItem> stockCheckItems = stockCheckItemService.list(Wrappers.<TertiaryStockCheckItem>query().eq("check_id", checkId).in("rfid", ucList));
        // 过滤掉当前盘库单中未盘明细得到已盘的
        List<TertiaryStockCheckItem> checkedItemList = stockCheckItems.stream().filter(s -> s.getCheckId().equals(checkId)).filter(stockCheckItem -> stockCheckItem.getCheckStatus() != -9).collect(Collectors.toList());
        List<TertiaryStockCheckItem> uncheckItemList = stockCheckItems.stream().filter(s -> s.getCheckId().equals(checkId)).filter(stockCheckItem -> stockCheckItem.getCheckStatus() == -9).collect(Collectors.toList());

        //HRP系统
        if (ParameterUtils.isStockcheckUseview()) {
            // 从HRP系统查询本次扫描到的RFID列表对应的库存--这些扫描到的RFID并不一定都在库存中
            List<HrpStockItemDTO> hrpStockItemDTOList = hrpService.getStockItem(ucList);
            List<String> rfidList = hrpStockItemDTOList.stream().map(HrpStockItemDTO::getRfid).collect(Collectors.toList());

            if (CollectionUtils.isNotEmpty(hrpStockItemDTOList)) {
                // 获取到能够查到库内的耗材的RFID列表
                List<String> rfids = hrpStockItemDTOList.stream().filter(s->StringUtils.isNotBlank(s.getRfid())).map(HrpStockItemDTO::getRfid).collect(Collectors.toList());
                List<String> warehouseCodes = hrpStockItemDTOList.stream().map(HrpStockItemDTO::getWarehouseCode).collect(Collectors.toList());
                // 相同的rfid集合rfids, 取得两个List的交集
                rfids.retainAll(ucList);

                // 遍历有HRP库存记录数据
                for (String rfid : rfids) {
                    //rfids都是能查到对应的库存的
                    Optional<HrpStockItemDTO> stockItemDTO = hrpStockItemDTOList.stream().filter(s->StringUtils.isNotBlank(s.getRfid())).filter(s -> s.getRfid().equals(rfid)).findFirst();
                    if (stockItemDTO.isPresent()) {
                        int num = hrpStockCheck(rfid, checkId, stockCheck, checkedItemList, stockItemDTO.get(),uncheckItemList);
                        if (num == 0) {
                            numNormal++;
                        }
                        if (num == -1) {
                            numLoss++;
                        }
                        if (num == 1) {
                            numSurplus++;
                        }
                        if (num == -9) {
                            numUnknown++;
                        }
                        if (num == -2) {
                            numNrepetitive++;
                        }
                    }
                }
            }
            int normal = stockCheckItemService.count(Wrappers.<TertiaryStockCheckItem>query().eq("check_id", checkId).eq("check_status", 0));
            if (normal == stockCheck.getStockNum()) {//理论库存已经全部被盘出来了
                msgBuffer = ", 该盘点单对应的盘点明细已经全部盘完，请核对盘点信息";
            } else {
                ucList.removeAll(rfidList);

                // 无HRP库存记录
                if (!ucList.isEmpty()) {
                    List<TertiaryStockCheckItem> checkedSurplusItems = stockCheckItemService.list(Wrappers.<TertiaryStockCheckItem>query().eq("check_id", checkId).in("rfid",ucList).eq("check_status", 1));
                    for (String rfid : ucList) {
                        int num = noStockCheckforHRP(rfid, checkId, checkedSurplusItems);
                        if (num == 1) {
                            numSurplus++;
                        }
                        if (num == -2) {
                            numNrepetitive++;
                        }
                    }
                }
            }

            if (normal < stockCheck.getStockNum() && CollectionUtils.isEmpty(hrpStockItemDTOList)) {
                msgBuffer = ", 本次扫描的RFID未查询到库存数据，请检查库存视图或者移动盘点位置";
            }
        }
        String ms = DateUtils.formatTime(System.currentTimeMillis() - beginTime);
        String msg = String.format("正常：%s个，盘亏：%s个，盘盈：%s个，未盘：%s个，重复：%s个，耗时：%s", numNormal, numLoss, numSurplus, numUnknown, numNrepetitive, ms);
        //更新盘盈盘亏未知
        restResult.setMsg(msg + msgBuffer);
        restResult.setData(this.updateMain(stockCheck));
        return restResult;
    }

    private static String selectF(String s) {
        String s1 = s;
        if (s.endsWith("F")) {
            s1 = selectF(s.substring(0, s.lastIndexOf("F")));
        }
        return s1;
    }

    private TertiaryStockCheck updateMain(TertiaryStockCheck stockCheck) {
        List<TertiaryStockCheckItem> stockCheckItems = stockCheckItemService.list(new QueryWrapper<TertiaryStockCheckItem>().eq("check_id", stockCheck.getId()));
        //盘点状态 0：正常 1：盘盈 -1：盘亏 -9：未盘
        stockCheck.setStockNormal((double) stockCheckItems.stream().filter(item -> item.getCheckStatus() == 0).count());
        stockCheck.setStockLoss((double) stockCheckItems.stream().filter(item -> item.getCheckStatus() == -1).count());
        stockCheck.setStockSurplus((double) stockCheckItems.stream().filter(item -> item.getCheckStatus() == 1).count());
        stockCheck.setStockUnknown((double) stockCheckItems.stream().filter(item -> item.getCheckStatus() == -9).count());
        this.updateById(stockCheck);
        return stockCheck;
    }

    private int hrpStockCheck(String rfid, String checkId, TertiaryStockCheck stockCheck, List<TertiaryStockCheckItem> stockCheckedItems, HrpStockItemDTO hrpStock, List<TertiaryStockCheckItem> unCheckItems) {
        TertiaryStockCheckItem stockCheckItem = new TertiaryStockCheckItem();
        int checkStatus = 0;//盘点状态 0：正常 1：盘盈 -1：盘亏 ， -9： 未盘， -2：重复盘点
        long count = stockCheckedItems.stream().filter(s -> s.getRfid().equals(rfid)).count();
        if (count > 0) {  //重复盘点
            return -2;
        }
        List<TertiaryStockCheckItem> thisCheckItems = unCheckItems.stream().filter(s -> s.getRfid().equals(rfid)).collect(Collectors.toList());
        if (CollectionUtils.isNotEmpty(thisCheckItems)) {
            stockCheckItem =  thisCheckItems.get(0);//由于是一物一码，就取第一个
            //理论上在库中对应的无库存数量
            if (hrpStock.getPackageQty() < 1) {
                checkStatus = 1;//数据库里面没有，结果实物有，则是盘盈  1：盘盈
            } else { //有库存数量
                checkStatus = 0;//如果存在说明该实物是正常的
            }
        } else {//防止数据出错，对应的RFID查到的数据被删掉了，这时我们只认为它是盘盈的
            BeanUtils.copyProperties(hrpStock, stockCheckItem);
            stockCheckItem.setRfid(rfid);
            checkStatus = 1;//数据库里面没有，结果实物有，则是盘盈  1：盘盈
        }

        stockCheckItem.setCheckStatus(checkStatus).setCheckId(checkId);
        stockCheckItemService.saveOrUpdate(stockCheckItem);
        return checkStatus;
    }

    /**
     * 扫描出的不在hrp数据视图中的RFID列表盘盈或者重复判断
     */
    private int noStockCheckforHRP(String rfid, String checkId, List<TertiaryStockCheckItem> checkedSurplusItems) {
        TertiaryStockCheckItem stockCheckItem = new TertiaryStockCheckItem();
        long count = checkedSurplusItems.stream().filter(s -> s.getRfid().equals(rfid)).count();
        //重复盘点
        if (count > 0) {
            return -2;
        }
        stockCheckItem.setRfid(rfid).setStockId("-1").setLineId("-1").setSupplierId("-1").setSupplierName("未知").setMatrName("未知");
        stockCheckItem.setCheckStatus(1).setCheckId(checkId);
        stockCheckItemService.saveOrUpdate(stockCheckItem);
        return 1;
    }

}
